#ifndef	_BASICS_H_
#define	_BASICS_H_

#pragma ident	"@(#)basics.h	1.18	06/03/16 SMI"

#ifdef	__cplusplus
extern "C" {
#endif

#include <sys/int_limits.h>
#include "hostos.h"
#include "hostcpu.h"
#include "options.h"

	/*
	 * Generic typedefs
	 *
	 * ... these type defs are so that the
	 * types can be used as pointers. The actual structure
	 * definitions are elsewhere.
	 */

typedef uint64_t	simcycle_t;

typedef struct SIMCPU	simcpu_t;
typedef struct EXEC_THREAD exec_thread_t;
typedef struct PROC_DEBUG proc_debug_t;

	/*
	 * Generic physical and virtual address types.
	 *
	 * Core design is 64 bit addressing, however some
	 * chips & cores may use 32bits in which case the
	 * bit widths should be explicit, but for the general
	 * infrastructure types use these two.
	 */

typedef	uint64_t	tpaddr_t;
typedef	uint64_t	tvaddr_t;

	/*
	 * Some simple debugging stuff
	 */

#ifdef NDEBUG
#define	ASSERT(_t)	do { } while (0)
#else
#include <assert.h>
#define	ASSERT(_t)	assert(_t)
#endif

#ifdef NDEBUG
#define	SANITY(_t)	do { } while (0)
#else
#define	SANITY(_t)	do { _t } while (0)
#endif

#ifdef NDEBUG
#define	DBG(s)		do { } while (0)
#define	LOG_INIT()	do { } while (0)
#else
extern uint64_t	debug_bits;
extern uint64_t	debug_bits_xor;
#define	DBG_BASIC	0x1
#define DBG(s)		do { if (debug_bits & DBG_BASIC) { s } } while (0)
#include "rotlog.h"
#define	LOG_INIT()	do { log_init(); } while (0)
#endif

	/*
	 * All non-essential printing now goes through one of these macros
	 * so that we can control what gets printed using the options.verbose
	 * flag.
	 */
extern options_t options;

#define	PRINTF(_s)	do { if (options.verbose) printf _s ; } while (0)
#define	FPRINTF(_s)	do { if (options.verbose) fprintf _s ; } while (0)
#define	LPRINTF(_s)	do { if (options.verbose) lprintf _s ; } while (0)
#define	WARNING(_s)	do { if (options.verbose) warning _s ; } while (0)

	/*
	 * Note: the following warnings are intended to be used as follows:
	 *
	 * FIXME_WARNING	Indended for stuff yet to be done. This warning is emitted
	 *			by code either partially complete or functionality not yet
	 *			implemented.
	 * IMPL_WARNING		Intended for warnings triggered by particular chip
	 *			implementation. e.g. accesses to certain register bit fields
	 *			that may not be used/legal on a particular implementation.
	 * EXEC_WARNING		Intended for errors/warnings for illegal / unusual behaviour
	 * 			of the code running on the simulator. Can be useful for
	 *			debugging the correct execution of code.
	 */

#ifdef NDEBUG
#define	FIXME_WARNING(_s)	do {  } while (0)
#define	IMPL_WARNING(_s)	do {  } while (0)
#define	EXEC_WARNING(_s)	do {  } while (0)
#else
#define	ONCE(_s)		do { static bool_t __once ; if (!__once) { __once = true; _s ; } }  while (0)
#define	FIXME_WARNING(_s)	ONCE( FPRINTF((stderr, "FIXME: ")); WARNING( _s );)
#define	IMPL_WARNING(_s)	ONCE( FPRINTF((stderr, "implementation ")); WARNING( _s );)
#define	EXEC_WARNING(_s)	do { FPRINTF((stderr, "execution ")); WARNING( _s ); } while (0)
#endif
	/*
	 * Macros used if simulator performance measurement is required
	 */

#if PERFORMANCE_CHECK	/* { */
#define	PERFDEF(_s)	_s
#define	PERF(_s)	do { _s ; } while (0)
#else			/* } { */
#define	PERFDEF(_s)
#define	PERF(_s)	do { } while (0)
#endif			/* } */

	/*
	 * Some simple maths macros
	 */

#define	Sizeof(_s)	((unsigned)sizeof(_s))

#define	INC_MOD(_val, _mod)	(((_val)+1)==(_mod) ? 0 : ((_val)+1))
#define	DEC_MOD(_val, _mod)	(((_val)-1)<0 ? ((_mod)-1) : ((_val)-1))


	/* This macro creates a 64bit (uint64_t) mask for the high to low bits specified */
	/* we could do this with just two shifts, but since most architectures have */
	/* a single pipelined shifter this is faster than waiting two shift latencies */
	/* Of course if constants are provided, then the compiler can do a better job */
	/* This also evaluates both high and low only once */

#define	MASK64( _high, _low )	( ( (uint64_t)((~(uint64_t)0)>>(63-(_high))) ) & ( (uint64_t)( (~(uint64_t)0)<<(_low)) ) )



	/*
	 * Basic functions we expect to be able to use everywhere
	 */

extern uint64_t sim_roundup(uint64_t value, uint64_t round);
#define HRT_TO_SEC( _x )	((_x) / NANOSEC)
#define HRT_TO_MILLISEC( _x )	((_x) / MICROSEC)


#ifdef	__cplusplus
}
#endif

#endif	/* _BASICS_H_ */
